/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package fr.ove.openmath.jome.ctrl.amto;

/**
 *
 * @author Mr.Sam
 */
import java.io.Serializable;
import java.util.*;
import fr.ove.utils.Factory;
import fr.ove.openmath.jome.ctrl.linear.events.*;
import fr.ove.openmath.jome.ctrl.amto.*;

/**
* An abstract tree structure of a mathematical object.
*
* @author © 1999 DIRAT Laurent
* @version 1.0  29/10/1999
*/
public abstract class AbstractMathTreeObject implements Serializable, Parametrable {
    /**
    * The identifier of the mathematical notion represented by the instance.
    */
    protected String identifier; // l'identificateur de l'objet

    /**
    * The parameter
    */
    protected String param;

    /**
    * The list of operands of the instance.
    */
    private Vector children; // les fils de l'instance (en qque sorte,les opérandes de l'objet en question)
    
    /**
    * The father of the instance in the tree structure
    */
    private AbstractMathTreeObject father = null;

    /**
    * The resources manager.<BR>
    * It is in charge of getting information according to the identifier.
    */
    private static AMTO_ResourcesManager resourcesManager = new AMTO_ResourcesManager("fr.ove.openmath.jome.ctrl.amto.AMTOResources");
    
    /**
    * The event source during the "flush" of the instance.<BR>
    */
    private /*static*/ LinearParserEventSource eventSource;
    
    // * This source is shared by all the instance
    // En fait il faudrait que ce soient toutes les instances filles qui partagent.
    // A voir plus tard une espèce de RootAbstractMathTreeObject, qui aurait une référence
    // sur la source et les filles de RootAbstractMathTreeObject partageraient cette référence.
    
    /**
    * The token which will identify the instance by the mean of the event sent.
    */
    protected int token;

    /**
    * The constructor.
    * @param identifier the identifier of the instance.
    * @param token the identifier of the instance by the mean of the event sent.
    */
    public AbstractMathTreeObject(String identifier, int token) {
        this.identifier = identifier;
        this.token = token;
        children = new Vector();
    }
    
    /**
    * Sets the event source.<BR>
    * The event source is shared by all the instances of AbstractMathTreeObject. So, the event source
    * must be set by the top most AbstractMathTreeObject (in the tree, so lets say the root of the formula)
    * object, and should only be done by this one.
    * @param eventSource the event source.
    */
    public void setEventSource(LinearParserEventSource eventSource) {
        this.eventSource = eventSource;
    }
    
    /**
    * Returns the event source.<BR>
    */
    public LinearParserEventSource getEventSource() {
        return eventSource;
    }
    
    /**
    * Fires the specified event.
    * @param linearParserEvent the event to fire.
    */
    public void fireLinearParserEvent(LinearParserEvent linearParserEvent) {
        eventSource.fireLinearParserEvent(linearParserEvent);
    }

    /**
    * Adds the object characterised by the specified identifier and parameter.
    * @param identifier the identifier of the object to add.
    * @param parameter the possible parameter of the object to add.
    * @returns the object added or <CODE>null</CODE>
    */
    public AbstractMathTreeObject add(String identifier, Object parameter) {
        String className = resourcesManager.getClassName(identifier);
        AbstractMathTreeObject newChild = (AbstractMathTreeObject) Factory.getClassInstance(className);
        newChild.eventSource = eventSource;  // Rajout parce que eventSource plus static
        if (newChild != null) {
            newChild.setParameter(parameter);
            children.addElement(newChild);
            newChild.setFather(this);
        }
        
        return newChild;
    }
    
    /**
    * Returns the child <CODE>AbstractMathTreeObject</CODE> at the specified index.
    * @param index the specified index.
    */
    public AbstractMathTreeObject getChild(int index) {
        return (AbstractMathTreeObject) children.elementAt(index);
    }

    /**
    * Returns the <CODE>AbstractMathTreeObject</CODE> children of the instance
    */
    public Vector getChildren() {
        return children;
    }

    /**
    * Returns the number of children of the instance
    */
    public int getNbChildren() {
        return children.size();
    }
    
    /**
    * Returns the father of the instance in the tree structure
    */
    public AbstractMathTreeObject getFather() {
        return father;
    }
    
    /**
    * Sets the father of the instance.
    * @param father the father to set to the instance
    */
    protected void setFather(AbstractMathTreeObject father) {
        this.father = father;
    }
    
    /**
    * Removes the specified child from the instance.
    * @param child the specified child to remove.
    */
    public void remove(AbstractMathTreeObject child) {
        child.setFather(null);
        children.removeElement(child);
    }
    
    /**
    * Removes the child at the specified index from the instance.
    * @param index the specified index of the child to remove.
    */
    public void remove(int index) {
        remove((AbstractMathTreeObject) children.elementAt(index));
    }

    /**
    * Removes all the children of the instance.
    */
    public void removeAll() {
        for (int i = children.size() - 1; i >= 0; i--)
            remove(0);
            
        children.trimToSize();
    }
    

    // En fait la plupart des objets ne sont pas paramétrales.
    // Seuls des objets correspondants aux variables, aux chiffres, .... le sont.
    
    /**
    * Sets the specified parameter.
    * @param param the parameter to set.
    */
    public void setParameter(Object param) {
        this.param = (String) param;
    }
    
    /**
    * Returns the parameter set before.
    */
    public Object getParameter() {
        return param;
    }
    
    // Fin de l'interface Parametrable
    
    
    /**
    * "Flushes" the object as a sequence of events for the building of the model.
    */
    public abstract void flush();    

    /**
    * "Flushes" the specified child.<BR>
    * According to their father, some children need to be between parenthesis to respect correctness of the
    * expression. So, when needed, the specified child is "flushed" as if it was between parenthesis.<BR>
    * @param child the child to "flush"
    * @param index the child index in the list of children of the instance.
    */
    protected void flushChild(AbstractMathTreeObject child, int index) {
        // The default is symply "flushing" the child.
        child.flush();
    }
}


